
use core::panic;

use super::physics;

type List<T> = ::std::vec::Vec<T>;
type Queue<T> = ::std::collections::VecDeque<T>;


#[derive(Debug)]
#[derive(Clone)]
#[derive(Default)]
pub struct CollisionBox
{
    shape: physics::Shape
}




#[derive(Debug)]
#[derive(Default)]
pub struct World
{
    width: f64,
    height: f64,
    gravity: f64,

    body_list: physics::BodyList
}

impl World
{
    pub fn new(width: f64, height: f64, gravity: f64) -> Self
    {
        Self {
            width,
            height,
            gravity,
            body_list: List::new()
        }
    }

    pub fn create_body(&mut self) -> &mut physics::Body
    {
        self.body_list.push(::std::default::Default::default());
        let len = self.body_list.len();
        self.body_list.get_mut(len - 1).unwrap()
    }

    pub fn get_body(&mut self, index: usize) -> Option<&mut physics::Body> { self.body_list.get_mut(index) }
}


#[derive(Debug)]
#[derive(Clone)]
pub enum CollisionEventType
{
    Cuboid,         // 两个长方体碰撞
    Ball,           // 两个球碰撞
    CuboidBall,     // 长方体与球碰撞
}
#[derive(Debug)]
#[derive(Clone)]
pub struct CollisionEvent
{
    r#type: CollisionEventType,
    b1: physics::Body,
    b2: physics::Body
}
type CollisionEventQueue = Queue<CollisionEvent>;

impl CollisionEvent
{
    pub fn new(r#type: CollisionEventType, b1: physics::Body, b2: physics::Body) -> Self
    {
        Self {
            r#type,
            b1,
            b2,
        }
    }

    pub fn get_bodys(&self) -> [&physics::Body; 2] { [&self.b1, &self.b2] }
    pub fn get_b1(&self) -> &physics::Body { &self.b1 }
    pub fn get_b2(&self) -> &physics::Body { &self.b2 }
}



/* 碰撞管道 */
#[derive(Default)]
#[derive(Clone)]
pub struct CollisionPipeline
{
    body_list: physics::BodyList,
    event_queue: CollisionEventQueue
}
impl CollisionPipeline
{
    pub fn new() -> Self { Default::default() }

    pub fn set_body_list(&mut self, list: physics::BodyList) { self.body_list = list; }
    pub fn get_body_list(&self) -> &physics::BodyList { &self.body_list }
    pub fn get_body_list_mut(&mut self) -> &mut physics::BodyList { &mut self.body_list }
    pub fn insert_body(&mut self, body: physics::Body) { self.body_list.push(body); }
    pub fn push_body(&mut self, body: physics::Body) { self.body_list.push(body); }

    pub fn get_event_queue(&self) -> &CollisionEventQueue { &self.event_queue }
    fn push_event(&mut self, event: CollisionEvent) { self.event_queue.push_back(event); }
    fn pop_event(&mut self) -> Option<CollisionEvent> { self.event_queue.pop_front() }


    pub fn update(&mut self)
    {
        // this
        let this_ptr = self as *mut CollisionPipeline;
        let option = unsafe { this_ptr.as_mut() };
        if option.is_none() { panic!(); }
        let this = option.unwrap();


        // body_list
        let body_list_ptr = &mut self.body_list as *mut physics::BodyList;
        let mut option = unsafe { body_list_ptr.as_mut() };
        let body_list_mut_i = option.unwrap();

        option = unsafe { body_list_ptr.as_mut() };
        let body_list_mut_j = option.unwrap();
        let body_list = &self.body_list;


        // for循环
        let count: usize = body_list.len();
        for i in 0..count// i 为 b1 索引
        {
            let b1 = body_list_mut_i.get_mut(i).expect("self.body_list.get(i) error");
            let mut b1_is_collision = false;
            let mut collision_body_list = physics::BodyList::new();
            for j in 0..body_list.len()// j 为 b2 索引
            {
                if i == j { continue; }// 如果b1 == b2 则下一个
                let b2 = body_list_mut_j.get_mut(j).expect("self.body_list.get(i) error");


                /* 是否碰撞 */
                // 碰撞事件类型
                let mut event_type: CollisionEventType = CollisionEventType::Cuboid;


                // 形状一样
                if b1.shape.r#type() == b2.shape.r#type()
                {
                    match &b1.shape.r#type()
                    {
                        physics::ShapeType::Rectangle(_, _) => {
                            /* Cuboid */
                            event_type = CollisionEventType::Cuboid;
                        },
                        physics::ShapeType::Polygon(_) => {
                            todo!();
                        },
                        physics::ShapeType::Circle(_) => {
                            /* Ball */
                            event_type = CollisionEventType::Ball;
                        },
                        physics::ShapeType::None => {
                            continue;// 判断下一个
                        }
                    }
                } else {
                    // 形状不一样
                    // CuboidBall
                    event_type = CollisionEventType::CuboidBall;
                }


                /* 添加事件到队列 */
                if b1.cross(&b2)
                {
                    this.push_event(
                        CollisionEvent { r#type: event_type, b1: b1.clone(), b2: b2.clone() }
                    );
                    collision_body_list.push(b2.clone());
                    if !b1_is_collision { b1_is_collision = true; }
                }
                
            }// for j in 0..body_list.len()


            // 如果 body 没有与任何物体碰撞，则没有受到支持
            if !b1_is_collision
            {
                b1.supported = false;
                continue;
            }


            if b1.supported { continue; }// 如果使 supported 则不进行后面的判断
            let shape_position = b1.shape_position();
            match b1.shape.r#type {
                physics::ShapeType::Rectangle(_, _) => {
                    let r1 = if let physics::ShapePosition::Rectangle(r) = shape_position {
                        r
                    } else { panic!() };

                    // 判断是否 supported
                    for b in collision_body_list
                    {
                        let r2 = if let physics::ShapePosition::Rectangle(r) = b.shape_position() {
                            r
                        } else { panic!() };

                        let r2height = r2.bottom - r2.top;
                        if  r1.bottom >= r2.top
                            && r1.bottom <= r2.top + (r2height / 8.0)
                            && r1.top < r2.top
                        {
                            b1.supported = true;
                            b1.position.y = r2.top - (r1.bottom - r1.top);
                            break;//已知道是supported，不用再判断了
                        }
                    }

                },
                physics::ShapeType::Polygon(_) => todo!(),
                physics::ShapeType::Circle(_) => todo!(),
                physics::ShapeType::None => panic!(),
            }
            
        }// for i in 0..count
    }


    /**
     * while (read_event().is_some())
     * {
     *     ......
     * }
     */
    pub fn read_event(&mut self) -> Option<CollisionEvent>
    {
        self.pop_event()
    }
}



pub enum PhysicsState {

}
type StateList = List<PhysicsState>;

/* 物理管道 */
#[derive(Default)]
pub struct PhysicsPipeline
{
    pub collision_pipeline: CollisionPipeline,
    state_list: StateList,
    g: f64
}
impl PhysicsPipeline
{
    pub fn new() -> Self { Default::default() }

    pub fn set_collision_pipeline(&mut self, cp: CollisionPipeline) { self.collision_pipeline = cp; }
    pub fn set_body_list(&mut self, list: physics::BodyList) { self.collision_pipeline.body_list = list; }
    pub fn get_body_list(&self) -> &physics::BodyList { &self.collision_pipeline.body_list }
    pub fn get_body_list_mut(&mut self) -> &mut physics::BodyList { &mut self.collision_pipeline.body_list }
    pub fn insert_body(&mut self, body: physics::Body) { self.collision_pipeline.body_list.push(body); }
    pub fn push_body(&mut self, body: physics::Body) { self.collision_pipeline.body_list.push(body); }


    pub fn set_g(&mut self, g: f64)
    {
        if self.g == g { return; }
        self.g = g;
        for b in self.get_body_list_mut()
        {
            b.gravity = b.mass * g;
        }
    }

    /// 更改数据后务必调用这个
    pub fn update_data(&mut self)
    {
        self.set_g(self.g);
    }

    pub fn update(&mut self, timedelta_seconds: f64)
    {
        self.collision_pipeline.update();
        loop
        {
            let option = self.collision_pipeline.read_event();
            if option.is_none() { break; }
            let e = option.unwrap();
            //println!("{:#?}", e);
            let mut b1 = e.b1;
            let mut b2 = e.b2;
            b1.collide_swap_force(&mut b2);
        }

        for b in self.get_body_list_mut()
        {
            b.update(timedelta_seconds);
        }
    }

}




#[cfg(test)]
mod tests {
    use super::*;
    use ::rand::Rng;

    #[test]
    fn test_physics_pipeline()
    {
        let cp = CollisionPipeline::new();
        let mut pp = PhysicsPipeline::new();
        
        pp.collision_pipeline = cp;

        let mut body_list = physics::BodyList::new();
        for _ in 0..1
        {
            let mut rng = ::rand::thread_rng();
            let mut body = physics::Body::default();
            body.supported = false;
            body.mass = 2.33;
            body.position.x = rng.gen_range(0.0..100.0);
            body.position.y = rng.gen_range(0.0..100.0);
            body.shape.r#type = physics::ShapeType::Rectangle(5.0, 5.0);
            body_list.push(body);
        }
        pp.set_body_list(body_list);
        pp.set_g(9.8);

        let start = ::std::time::Instant::now();
        let mut timedelta: f64 = 0.0;
        let mut count = 0;
        loop {
            pp.update(timedelta);

            for b in pp.get_body_list()
            {
                println!("{:#?}", b);
            }

            eprintln!("{}", count);
            if timedelta > 2.0 {
                break;
            }
            count += 1;
            timedelta = start.elapsed().as_secs_f64();
        }
    }
}


